# -*- coding: utf-8 -*-
# -*- python -*-
"""
 util.py

 by Jacob Smith <http://code.google.com/p/lua-mpi/>
 Copyright (C) 2009 Jacob Smith, All Rights Reserved

 $Id: util.py 11 2009-07-01 08:02:38Z kloptops $
"""

__all__ = [];
import sys, os, re


__all__ += ['path', 'abspath', 'isdir', 'isfile']
def path(*args):
    """Returns path"""
    result=os.path.join(*args)
    return result

def abspath(*args):
    """Returns abs path"""
    result=path(*args)
    if not os.path.isabs(result):
        result=os.path.abspath(result)
    return result

def isdir(path):
    return os.path.isdir(path)

def isfile(path):
    return os.path.isfile(path)

__all__ += ['saveraw', 'loadraw']
def saveraw(file, data):
    try:
        open(file, 'wb').write(data)
    except IOError, err:
        print "Error: saveraw: " + str(file) + ": " + err
        pass

def loadraw(file, default=None):
    try:
        return open(file, 'rb').read()
    except IOError:
        return default



__all__ += ['ZoneException', 'Zones']
class ZoneException(Exception):
    pass

class Zones(object):

    # Zone Tags
    # C
    #   /* *** BEGIN BLAH *** */
    #   /* *** END BLAH *** */
    # C++
    #   // /// BEGIN BLAH /// //
    #   // /// END BLAH /// //
    # Python / Perl
    #   ## ### BEGIN BLAH ### ##
    #   ## ### END BLAH ### ##
    # Lua
    #   -- --- BEGIN BLAH --- --
    #   -- --- END BLAH --- --
    __boundry_re = re.compile(r'^\s*(?:/\*|//|##|--)\s+(?:#|/|\*|-){3}\s+(BEGIN|END)[\s_]+([A-Z_\s]+)\s+(?:#|/|\*|-){3}\s+(?:\*/|//|##|--)\s*$', re.I)

    def __init__(self, data=None):
        self.clean()

        if data:
            self.unpack(data)

    def clean(self):
        self.zone_count = 0
        self.zones = {}
        self.zone_data = [
            {'name': None, 'lines': []},
            ]

    # Internal functions to make life easier...
    def _add_zone(self, name=None):
        self.zone_data.append({'name': name, 'lines': []})
        self.zone_count += 1
        if name:
            self.zones[name] = self.zone_count

    def _add_line(self, line):
        self.zone_data[self.zone_count]['lines'].append(line)

    def _last_zone(self):
        return self.zone_data[self.zone_count]['name']

    def unpack(self, data):
        lines = data.replace('\r', '').split('\n')

        self.clean()

        for line_no, line in enumerate(lines):
            boundry_match = self.__boundry_re.match(line)

            if boundry_match:
                boundry_type, boundry_name = map(lambda x: x.upper(), boundry_match.groups())
                boundry_name = boundry_name.replace('_', ' ')

                if boundry_type == 'BEGIN':
                    if not (self._last_zone() == None):
                        raise ZoneException, "unpack: %d: imballanced zone '%s'" % \
                            (line_no, self._last_zone())

                    if self.zones.has_key(boundry_name):
                        raise ZoneException, "unpack: %d: duplicate zone '%s' found" % \
                            (line_no, self._last_zone())

                    self._add_line(line)
                    self._add_zone(boundry_name.upper())

                elif boundry_type == 'END':
                    if not (self._last_zone() == boundry_name):
                        raise ZoneException, "unpack: %d: zone missmatch, expected '%s' got '%s'" % \
                            (line_no, self._last_zone(), boundry_name)

                    self._add_zone(None)
                    self._add_line(line)

            else:
                self._add_line(line)

    def zone_list(self):
        return self.zones.keys()

    def get(self, zone):
        zone = zone.upper().replace('_', ' ')

        if not self.zones.has_key(zone):
            raise ZoneException, "get: zone '%s' not found" % \
                (zone)

        return self.zone_data[self.zones[zone]]['lines']

    def replace(self, zone, data):
        zone = zone.upper().replace('_', ' ')
        lines = data.replace('\r', '').split('\n')

        if not self.zones.has_key(zone):
            raise ZoneException, "replace: zone '%s' not found" % \
                (zone)

        self.zone_data[self.zones[zone]]['lines'] = lines

    def pack(self):
        return '\n'.join(filter(lambda x: x != '', map(lambda x: '\n'.join(x['lines']), self.zone_data)))
